home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / window2.zip / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-01-04  |  16KB  |  562 lines

  1. /*    module:        window.c
  2.  *    programmer:    Ray L. McVay
  3.  *    started:    1 Aug 84
  4.  *    version:    1.2, 23 Aug 84
  5.  *    version:    1.3, 14 Jun 86 as modified by Larry A. Thiel
  6.  *                                (I hope this version # doesn't conflict)
  7.  *
  8.  *    A simple window package based on the article and programs
  9.  *    by Edward Mitchell in the Jan 84 Dr. Dobb's Journal.  This
  10.  *    implementation uses dynamically allocated buffers for the
  11.  *    window control blocks and screen save buffers.
  12.  *
  13.  *    An assembly language support library called VLIB is used to
  14.  *    interface the DeSmet C compiler with the IBM ROM BIOS video
  15.  *    routines.  VLIB will undoubtedly have to be rewritten if the
  16.  *    window package is to be used with other compilers.
  17.  *
  18.  *    History -
  19.  *
  20.  *    1.1    -    Added style member to wcb structure, clr_window() and
  21.  *            use of wn->cx for horizontal scrolling in write_text().
  22.  *
  23.  *    1.2 -    Added oldx, oldy members to wcb structure and use them
  24.  *            in draw_window() and remove_window().
  25.  *
  26.  *    1.3 -    Added wpage member to wcb structure, functions pputch(),
  27.  *             pgetch(), and pdraw_row() to window.c, and get_page() to vlib.a
  28.  *             to permit windows on video pages other than 0.
  29.  *            Added win_write() to provide better treatment of the window as
  30.  *             a glass tty. Requires care if old method used for horizontal
  31.  *             scrolling.
  32.  *            Added ticker() and wticker() to window.c, get_curtyp(), kbd_ci(),
  33.  *             and kbd_csts for ticker tape input with editing. ticker() may be
  34.  *             used without a window. kbd_csts() is not used here but is
  35.  *             available for use.
  36.  */
  37.  
  38. #include    <stdio.h>
  39. #include    <window.h>
  40.  
  41. #define HOME        0x8A    /* HOME key    */
  42. #define CURLF        0x8B    /* <-        */
  43. #define ENDKEY        0x8C    /* END key    */
  44. #define CURRT        0x9B    /* ->        */
  45. #define INSERT        0x9D    /* Ins        */
  46. #define DELETE        0x9E    /* Del        */
  47.  
  48.     /*********************
  49.     ** desmet functions    */
  50.  
  51. int        isprint();
  52.  
  53.     /*********************
  54.     ** vlib1 functions    */
  55.  
  56. int        get_page(), get_curtyp(), getxy(), vgetc();
  57. void    gotoxy(), set_curtyp(), scrlup(), scrldn(), vputc(), vputca();
  58.  
  59. /************************************************************************
  60. * putch(), write a character and attribute to a specific XY location on *
  61. *           the screen. The attribute is the high byte of the character.    *
  62. ************************************************************************/
  63.  
  64. void pputch(x, y, c)
  65. int        x, y, c;
  66. {
  67.     gotoxy(x, y, 0);
  68.     vputca(c, 0, 1);
  69. }
  70.  
  71.  
  72. /*************************************************
  73. * pputch(), same as putch except uses page arg    **
  74. *************************************************/
  75.  
  76. void putch(x, y, c, page)
  77. int        x, y, c;
  78. {
  79.     gotoxy(x, y, page);
  80.     vputca(c, page, 1);
  81. }
  82.  
  83.  
  84. /************************************************************************
  85. * getch(), return the character and attribute at screen XY                *
  86. ************************************************************************/
  87.  
  88. int getch(x, y)
  89. int        x, y;
  90. {
  91.     gotoxy(x, y, 0);
  92.     return(vgetc(0));
  93. }
  94.  
  95.  
  96. /*************************************************
  97. * pgetch(), same as getch except uses page arg    **
  98. *************************************************/
  99.  
  100. int pgetch(x, y, page)
  101. int        x, y;
  102. {
  103.     gotoxy(x, y, page);
  104.     return(vgetc(page));
  105. }
  106.  
  107.  
  108. /************************************************************************
  109. * draw_row(), output a row of one character/attribute at XY                *
  110. ************************************************************************/
  111.  
  112. void draw_row(x, y, count, c)
  113. int        x, y, count,c;
  114. {
  115.     gotoxy(x, y, 0);
  116.     vputca(c, 0, count);
  117. }
  118.  
  119.  
  120. /********************************************************
  121. * pdraw_row(), same as draw_row except uses page arg    *
  122. ********************************************************/
  123.  
  124. void pdraw_row(x, y, count, c, page)
  125. int        x, y, count,c;
  126. {
  127.     gotoxy(x, y, page);
  128.     vputca(c, page, count);
  129. }
  130.  
  131.  
  132. /************************************************************************
  133. * draw_window(), open a window of given size with upper left corner at    *
  134. *                 XY. Allocates buffers for the window control block and *
  135. *                 screen save buffers. Copies overwritten screen to the    *
  136. *                 buffer. Draws the blank window. Returns the address of    *
  137. *                 the window control block or NULL if no buffer space.    *
  138. ************************************************************************/
  139.  
  140. WINDOWPTR draw_window(x, y, width, height, attrib)
  141. int        x, y, width, height, attrib;
  142. {
  143.     WINDOWPTR wn;
  144.     int        tx, ty,
  145.             xend, yend;
  146.     int        *tptr;
  147.     char    *calloc();
  148.  
  149.     if ((wn = (WINDOWPTR)calloc(1, sizeof(WINDOW))) == NULL)
  150.         return(NULL);
  151.     else if ((wn->scrnsave = (int *)calloc((width+2) * (height+2), sizeof(int))) == NULL)
  152.     {
  153.         free(wn);
  154.         return(NULL);
  155.     }
  156.     else
  157.     {
  158.         /* store parameters in window control block */
  159.  
  160.         wn->wpage = get_page();                /* what video page are we on    */
  161.         wn->ulx = x;
  162.         wn->uly = y;
  163.         wn->xsize = width;
  164.         wn->ysize = height;
  165.         wn->cx = 1;
  166.         wn->cy = 1;
  167.         wn->style = attrib;
  168.         attrib <<= 8;    /* will make things below go quicker */
  169.         tx = getxy(wn->wpage);
  170.         wn->oldx = tx & 255;
  171.         wn->oldy = tx >> 8;
  172.  
  173.         /* Copy existing text where the window will be placed */
  174.         /* to the scrnsave buffer. Obviously, a less portable */
  175.         /* routine could be much faster.                      */
  176.  
  177.         tptr = wn->scrnsave;
  178.         xend = x + width + 2;
  179.         yend = y + height + 2;
  180.  
  181.         for (ty = y; ty < yend; ty++)
  182.         {
  183.             for (tx = x; tx < xend; tx++)
  184.                 *tptr++ = pgetch(tx, ty, wn->wpage);
  185.         }
  186.  
  187.         /* draw the window border and clear the text area */
  188.  
  189.         pputch(x, y, 0xda + attrib, wn->wpage);                    /* ul corner */
  190.         pdraw_row(x + 1, y, width, 0xc4 + attrib, wn->wpage);    /* horiz bar */
  191.         pputch(x + width + 1, y, 0xbf + attrib, wn->wpage);        /* ur corner */
  192.  
  193.         yend = y + height;
  194.  
  195.         for (ty = y+1; ty <= yend; ty++)
  196.         {
  197.             pputch(x, ty, 0xb3 + attrib, wn->wpage);            /* draw the sides */
  198.             pputch(x+width+1, ty, 0xb3 + attrib, wn->wpage);
  199.         }
  200.  
  201.         pputch(x, y + height + 1, 0xc0 + attrib, wn->wpage);                /* ll corner */
  202.         pdraw_row(x + 1, y + height + 1, width, 0xc4 + attrib, wn->wpage);    /* horiz bar */
  203.         pputch(x + width + 1, y + height + 1, 0xd9 + attrib, wn->wpage);    /* lr corner */
  204.  
  205.         clr_window(wn);
  206.  
  207.         return(wn);
  208.     }
  209. }
  210.  
  211.  
  212. /************************************************************************
  213. * remove_window(), erase the window at the window control block.        *
  214. *                   Must be the "top" window if overlapping windows are  *
  215. *                   used. "Tiled" windows could be removed randomly.        *
  216. ************************************************************************/
  217.  
  218. void remove_window(wn)
  219. WINDOWPTR wn;
  220. {
  221.     int        tx, ty,
  222.             xend, yend;
  223.     int        *tptr;
  224.  
  225.     /* just repaint the saved text at the appropriate location */
  226.  
  227.     tptr = wn->scrnsave;
  228.     xend = wn->ulx + wn->xsize + 2;
  229.     yend = wn->uly + wn->ysize + 2;
  230.  
  231.     for (ty = wn->uly; ty < yend; ty++)
  232.     {
  233.         for (tx = wn->ulx; tx < xend; tx++)
  234.             pputch(tx, ty, *tptr++, wn->wpage);
  235.     }
  236.  
  237.     /* put cursor back where it was before this rude interruption */
  238.  
  239.     gotoxy(wn->oldx, wn->oldy, wn->wpage);
  240.  
  241.     /* then release the dynamic storage used */
  242.  
  243.     free(wn->scrnsave);
  244.     free(wn);
  245. }
  246.  
  247.  
  248. /************************************************************************
  249. * write_text(), print a string inside a window using cx, cy in WCB        *
  250. ************************************************************************/
  251.  
  252. void write_text(wn, string)
  253. WINDOWPTR wn;
  254. char    *string;
  255. {
  256.     int        tx, ty, xend;
  257.  
  258.     /* first check to see if we're at the bottom of the window        */
  259.     /* if we are then scroll the contents of the window up            */
  260.  
  261.     if (wn->cy > wn->ysize)
  262.     {
  263.         delete_row(wn, 1);
  264.         --wn->cy;
  265.     }
  266.  
  267.     /* Print as much of the string as will fit in the window.        *
  268.      * cx is used for relative left margin. If cx is negative then    *
  269.      * the first cx characters will be removed from the string to    *
  270.      * allow horizontal scrolling in the window.                    *
  271.      * NOTE: This obviously simple-minded technique is usable for    *
  272.      *          displaying predetermined messages but a more general    *
  273.      *         console output intercept should be used for Star-like    *
  274.      *         environments.                                            */
  275.  
  276.     if (wn->cx > 0)
  277.         tx = wn->ulx + wn->cx;
  278.     else
  279.     {
  280.         if (-wn->cx < strlen(string))
  281.             string -= wn->cx;
  282.         else
  283.             *string = '\0';
  284.         tx = wn->ulx + 1;
  285.     }
  286.     xend = wn->ulx + wn->xsize + 1;
  287.     ty = wn->uly + wn->cy;
  288.     while ((tx < xend) && *string)
  289.     {
  290.         gotoxy(tx++, ty, wn->wpage);
  291.         vputc(*string++, wn->wpage, 1);
  292.     }
  293.     ++wn->cy;        /* move the internal cursor to the next line */
  294. }
  295.  
  296.  
  297.     /*****************************************************************
  298.     ** Another function to write text to a window. This one uses the**
  299.     ** window like a glass teletype and processes certain control    **
  300.     ** characters. As a result, it will not do the right thing if    **
  301.     ** you send it '\n' or '\r' chars after changing wn->cx to cause**
  302.     ** horizontal scrolling. Tabs are NOT expanded.                    */
  303.  
  304. void win_text(wn,cptr)
  305.  
  306.     WINDOWPTR    wn;
  307.     char        *cptr;
  308. {
  309.     /* draw_window() does not position cursor AND     **
  310.     ** user may have moved it anyway, so start by    **
  311.     ** putting it where it belongs.                    */
  312.  
  313.     gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
  314.  
  315.     while ( *cptr )
  316.     {
  317.         switch ( *cptr )
  318.         {
  319.             case '\n':    wn->cy++;
  320.                         if ( wn->cy > wn->ysize )    /* if past bottom of    */
  321.                         {    delete_row ( wn, 1 );    /*    window, scroll up    */
  322.                             --wn->cy;
  323.                         }                            /* pass thru to '\r'    */
  324.             case '\r':    wn->cx = 1;
  325.                         break;
  326.             case 7:        co (*cptr);                    /* just ring bell        */
  327.                         break;
  328.             case '\t':    *cptr = ' ';                /* replace tab & pass on*/
  329.             default:    if ( wn->cx <= wn->xsize )
  330.                             vputc ( *cptr, wn->wpage, 1 );
  331.                         wn->cx++;
  332.         }
  333.         gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
  334.         cptr++;
  335.     }
  336. }
  337.  
  338. /************************************************************************
  339. * insert_row(), insert a row of blanks by scrolling the lower portion    *
  340. *                of a window down                                        *
  341. ************************************************************************/
  342.  
  343. void insert_row(wn, row)
  344. WINDOWPTR wn;
  345. int        row;
  346. {
  347.     int        scrlwn[4];
  348.  
  349.     /* calculate corners of the scrolling window */
  350.  
  351.     scrlwn[0] = wn->ulx + 1;            /* ulx */
  352.     scrlwn[1] = wn->uly + row;            /* uly */
  353.     scrlwn[2] = wn->ulx + wn->xsize;    /* lrx */
  354.     scrlwn[3] = wn->uly + wn->ysize;    /* lry */
  355.  
  356.     scrldn(scrlwn, 1, wn->style);
  357. }
  358.  
  359.  
  360. /************************************************************************
  361. * delete_row(), delete a row by scrolling the lower portion of a window *
  362. *                up and inserting a row of blanks at the bottom row        *
  363. ************************************************************************/
  364.  
  365. void delete_row(wn, row)
  366. WINDOWPTR wn;
  367. int        row;
  368. {
  369.     int        scrlwn[4];
  370.  
  371.     /* calculate corners of the scrolling window */
  372.  
  373.     scrlwn[0] = wn->ulx + 1;            /* ulx */
  374.     scrlwn[1] = wn->uly + row;            /* uly */
  375.     scrlwn[2] = wn->ulx + wn->xsize;    /* lrx */
  376.     scrlwn[3] = wn->uly + wn->ysize;    /* lry */
  377.  
  378.     scrlup(scrlwn, 1, wn->style);
  379. }
  380.  
  381.  
  382. /************************************************************************
  383. * clr_window(), clear the "active" part of a window    and "home" internal    *
  384. *                text cursor                                                *
  385. ************************************************************************/
  386.  
  387. void clr_window(wn)
  388. WINDOWPTR wn;
  389. {
  390.     int        scrlwn[4];
  391.  
  392.     /* calculate corners of the scrolling window */
  393.  
  394.     scrlwn[0] = wn->ulx + 1;            /* ulx */
  395.     scrlwn[1] = wn->uly + 1;            /* uly */
  396.     scrlwn[2] = wn->ulx + wn->xsize;    /* lrx */
  397.     scrlwn[3] = wn->uly + wn->ysize;    /* lry */
  398.  
  399.     scrlup(scrlwn, 0, wn->style);
  400.     wn->cx = 1;
  401.     wn->cy = 1;
  402. }
  403.  
  404.     /*********************************************************************
  405.     ** Operator edit of null terminated string in buffer at ptr. Buffer    **
  406.     ** size must be > max bytes and function will allow result to be up    **
  407.     ** to max bytes in length. Function may be called with an empty        **
  408.     ** string for entry of all new data. Function will use width chars    **
  409.     ** at row, col of video page page to display a ticker tape of the    **
  410.     ** working string. Function returns the length of the result.        */
  411.  
  412. int ticker(row,col,ptr,max,width,page)
  413.  
  414.     int        row, col, max, width;
  415.     char    *ptr;
  416. {
  417.     int        i, j, toffset, tcur, spos, count, key, repl;
  418.     int        rwright, rwleft, repl, vlines, oldcbeg, oldcend;
  419.     char    *cptr, *lptr;
  420.  
  421.     i = get_curtyp();
  422.     oldcbeg = i >> 8;
  423.     oldcend = i & 255;
  424.     vlines = ( get_mode() == 7 ) ? 13 : 7;
  425.     toffset = tcur = spos = count = repl = 0;
  426.     i = ( repl ) ? vlines - 1 : 0;
  427.     set_curtyp ( i, vlines );
  428.     gotoxy ( col, row, page );
  429.     vputc ( ' ', page, width );
  430.     cptr = ptr;
  431.     while ( *cptr++ )
  432.         count++;
  433.     rwleft = 0;
  434.     rwright = 1;
  435.     while ( 1 )
  436.     {    if ( rwleft )
  437.         {    for ( i=0, cptr = ptr + toffset; i < (width-1); i++ )
  438.             {    gotoxy ( col + i, row, page );
  439.                 vputc ( *cptr++, page, 1 );
  440.             }
  441.             rwleft = 0;
  442.         }
  443.         if ( rwright )
  444.         {    i = tcur;
  445.             cptr = ptr + spos;
  446.             while ( i < width )
  447.             {    gotoxy ( col + i++, row, page );
  448.                 if ( *cptr )
  449.                 {    vputc ( *cptr++, page, 1 );
  450.                 }
  451.                 else
  452.                 {    vputc ( ' ', page, 1 );
  453.                     break;
  454.                 }
  455.             }
  456.             rwright = 0;
  457.         }
  458.         gotoxy ( col + tcur, row, page );
  459.         key = kbd_ci();
  460.         if ( isprint (key) )
  461.             goto prt_char;                            /* not control key        */
  462.  
  463.         if ( key == 8 )
  464.         {    if ( spos < 1 )                            /* backspace            */
  465.                 goto bad_key;
  466.             tcur--;
  467.             spos--;
  468.             key = DELETE;
  469.         }
  470.         if ( key == 7 )
  471.             key = DELETE;                            /* change ^G to DELETE    */
  472.         if ( key == DELETE )
  473.         {    if ( spos >= count )                    /* Delete key            */
  474.                 goto bad_key;
  475.             cptr = ptr + spos;
  476.             lptr = cptr + 1;
  477.             while ( *cptr )
  478.                 *cptr++ = *lptr++;
  479.             count--;
  480.             rwright = 1;
  481.         }
  482.         if ( (key == CURLF) || (key == 19) )
  483.         {    if ( spos < 1 )                            /* Left arrow or ^S        */
  484.                 goto bad_key;
  485.             tcur--;
  486.         }
  487.         if ( (key == CURRT) || (key == 4) )
  488.         {    if ( spos >= count )                    /* Right arrow or ^D    */
  489.                 goto bad_key;
  490.             tcur++;
  491.         }
  492.         if ( (key == 22) || (key == INSERT) )
  493.         {    repl = -1 - repl;                        /* Insert key or ^V        */
  494.             i = ( repl ) ? vlines - 1 : 0;
  495.             set_curtyp ( i, vlines );
  496.         }
  497.         if ( key == HOME )
  498.             tcur = -toffset;                        /* Home key                */
  499.         if ( key == ENDKEY )
  500.             tcur = count - toffset;                    /* End Key                */
  501.         if ( key == '\r' )
  502.         {    set_curtyp ( oldcbeg, oldcend );
  503.             return ( count );                        /* Return key            */
  504.         }
  505.         goto cur_chk;
  506. prt_char:
  507.         if ( spos >= max )
  508.             goto bad_key;                            /* at end of full string*/
  509.         if ( repl && (spos < count) )
  510.             goto repl_char;                            /* replace mode            */
  511.         if ( count >= max )
  512.             goto bad_key;                            /* no room to insert key*/
  513.         i = ++count - spos;
  514.         cptr = ptr + count;
  515.         lptr = cptr - 1;
  516.         while ( i-- )                                /* make room for key    */
  517.             *cptr-- = *lptr--;
  518.         rwright = 1;
  519. repl_char:
  520.         cptr = ptr + spos;
  521.         *cptr = key;
  522.         vputc ( *cptr, page, 1 );
  523.         tcur++;
  524. cur_chk:
  525.         if ( tcur < 0 )
  526.         {    toffset += tcur;
  527.             tcur = 0;
  528.             rwright = 1;
  529.         }
  530.         if ( tcur >= width )
  531.         {    toffset += tcur - width + 1;
  532.             tcur = width - 1;
  533.             if ( (toffset + tcur) >= max )
  534.                 toffset--;
  535.             rwleft = 1;
  536.             rwright = 1;
  537.         }
  538. bad_key:
  539.         spos = toffset + tcur;
  540.     }
  541. }
  542.  
  543.     /*****************************************
  544.     ** edit string (see ticker()) in window    */
  545.  
  546. int wticker(wn,ptr,max,width)
  547.  
  548.     WINDOWPTR    wn;
  549.     char        *ptr;
  550.     int            max, width;
  551. {
  552.     int            i, row, col, page;
  553.  
  554.     row = wn->uly + wn->cy;
  555.     col = wn->ulx + wn->cx;
  556.     page = wn->wpage;
  557.     i = wn->xsize - wn->cx + 1;
  558.     if ( (i < width) && (i > 0) )
  559.         width = i;
  560.     return ( ticker ( row, col, ptr, max, width, page ) );
  561. }
  562.